package com.videomaru.component
{
	import com.videomaru.Log;
	import com.videomaru.MaruEvent;
	import com.videomaru.MaruPlayer;
	
	import fl.core.InvalidationType;
	import fl.core.UIComponent;
	
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.FrameLabel;
	import flash.display.MovieClip;
	import flash.display.Stage;
	import flash.display.StageAlign;
	import flash.display.StageDisplayState;
	import flash.display.StageScaleMode;
	import flash.events.FullScreenEvent;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.utils.*;
	
	/********************************************************************
	 * MaruComponent class
	 * This is the class that wraps the core classes in video.Maru so
	 * designers and others that don't like code can use it. The class
	 * detects the presence of MovieClips with certain names and pass
	 * these on to it's internal instance of com.videomaru.MaruPlayer.
	 * 
	 * The player part of the component can still be controlled using 
	 * code through the "player" public variable (player is the 
	 * MaruPlayer instance).
	 * 
	 * Example: adding a file to the players playlist:
	 * myComponentInstance.player.addFile("something.flv")
	 * 
	 * NOTE: When you open the project in Flex, you will see 4 Warnings.
	 *       This is really not my fault since it's in the distribution
	 *       version of Adobe's UIComponent files and I don't think I'm
	 *       technically allowed to fix their bugs in the files that
	 *       come with the Flash IDE (EULA issue)?
	 * 
	 * PRERREQUISITES
	 * for compiling a new version of this component:
	 * 
	 * 1. Connect to the SVN repository and update it to make sure you
	 *    have the latest version of all files. You need to do this for
	 *    both the component and core classes (if required).
	 * 2. Make sure that you add this to Flash's global classpath, or you
	 *    will get errors saying that UIComponent cannot be found:
	 *    $(AppConfig)/Component Source/ActionScript 3.0/User Interface/
	 * 3. Make any changes to the files
	 * 
	 * COMPILING A NEW VERSION
	 * 
	 *    Update the classpath in this FLA to reflect the location of
	 *    the videoMaru core classes:
	 *    File > Publish Settings > Flash > Settings > Classpath
	 *   
	 *    (This should point to the folder with the root of the videoMaru
	 *    class hierarchy that has a folder named "com" with a subfolder
	 *    named "videomaru"). Close dialogue when done.
	 * 1. Open the MaruComponent project in Flex.
	 * 2. Open the "videoMaruComponentClasses_as3.fla" in the Flash IDE.
	 * 3. Delete the existing "MaruPlayerClasses SWF" Compiled Clip
	 *    symbol from the library.
	 * 4. (Optional) If you need an updated SWC file (for use with Flex 
	 *    or Flash), right clicki the "MaruPlayerClasses" MovieClip and 
	 *    select "Export SWC file..."
	 * 5. Right click the "MaruPlayerClasses" MovieClip and select
	 *    "Convert to Compiled Clip". this will generate a new compiled
	 *    clip that reflects any changes.
	 * 6. Open "videoMaruComponent_as3.fla" and double click the
	 *    "MaruPlayer" component in the library to edit it
	 * 7. On frame two of the "assets" layer, delete the existing 
	 *    "MaruPlayerClasses SWF" compiled clip.
	 * 8. Copy the newly compiled classes onto frame two of the "assets"
	 *    layer.
	 * 9. Right click the MaruPlayer component and select the "Component
	 *    Definition..." option.
	 * 10.Click OK to "recompile" the component so that changes are
	 *    shown.
	 * 11.If no errors occured, the new component is ready to be used
	 * 
	 * COMPONENT HISTORY
	 * The MaruComponent is based on the UIComponent classes that ship
	 * with Flash CS3. It follows the general guidelines for CS3
	 * components, but we've had to do some simplifications. The most
	 * important for this component is not code-compliance but rather
	 * user friendlyness.
	 * 
	 * Version 1 (10th Dec 2007)
	 * The first version of this component did a detection of the clips
	 * available on stage and then applied listeners and custom code to
	 * each of these. This is a really error prone approach for several
	 * reasons:
	 * 
	 * 1. video.Maru is primarily used by designers that may do things
	 *    it is hard to account for. What if there's several play-
	 *    buttons on stage (due to accidental duplication or even on
	 *    purpose). This will cause reference problems.
	 *    
	 * 2. What if a button exist on frame 1, but not 2? That could
	 *    produce "ghost" buttons that were never cleared from memory
	 *    since they still had listners applied. While theoretically
	 *    possible, this would require us to loop through the whole
	 *    DisplayList on every frame. If we do this in a huge file, it
	 *    could potentially crash the Flash Player.
	 * 3. The DisplayList hierarchy is prone to error when it comes to
	 *    basing the component on instance names. I've discovered that
	 *    in certain cases, the component will only be able to list
	 *    MovieClips on the layers BELOW itself, not those ABOVE. This
	 *    is a major issue since we have no control over this, it is 
	 *    hard to reproduce consistently and we have no control over
	 *    what the user actually does on the timeline.
	 * 
	 * Version 2 (18th Dec 2007)
	 * Based on the issues in v1, we're now basing the component on
	 * listening for clicks on the Stage-property of the MaruComponent
	 * and rather check if the object clicked is a MovieClip and has one
	 * of the predefined names. This approach will solve the above 
	 * issues, unless propagation is stopped in some way (unlikely).
	 * 
	 * This will require a small change to buttons though. They must now
	 * issue their own stop-command on the first frame. The v2 approach
	 * also reduced the component code to half the size and makes it
	 * MUCH less error prone. Simpler is (usually) better!
	 * 
	 * Version 3 (8th April 2008)
	 * First version committed to CVS. Fixed several bugs and added
	 * the timeline/playhead functionality as well as progress bars.
	 * 
	 * Supported controls in this release:
	 * 
	 * Buttons
	 * - playpause_btn
	 * - play_btn
	 * - pause_btn
	 * - stop_btn
	 * - soundoff_btn
	 * - soundon_btn
	 * - soundonoff_btn
	 * - fullscreen_btn
	 * 
	 * Sliders
	 * - volumeRange
	 * - volumeSlider
	 * - timeline
	 * - playhead
	 * - downloadProgress
	 * 
	 * (as defined in the "possibleButtons" array)
	 * 
	 *******************************************************************/
	
	public class MaruComponent extends UIComponent
	{
		public  var player:MaruPlayer;
		
		public  var _filename:String = "http://www.flashgamer.com/maru/bravia_700Kbps.flv";
		private var _fullscreenEnabled:Boolean;
		private var _autoplay:Boolean;
		private var _autorewind:Boolean;
		private var _autosize:Boolean;
		private var _fadeTrayDelay:Number;
		private var _fadeTrayDuration:Number;
		private var _loopmode:String;
		private var _scaleMode:String;
		private var _debug:Number;
		
		private var possibleButtons:Array;
		private var volumeSliderMC:MovieClip;
		private var volumeRangeMC:MovieClip;
		private var volumeDragged:Boolean = false;
		private var timelineMC:MovieClip;
		private var playheadMC:MovieClip;
		private var playProgressMC:MovieClip;
		private var downloadProgressMC:MovieClip;
		private var timelinePlayStatus:Boolean;
		
		private var playbackPercent:Number;
		
		private var oldX:Number;
		private var oldY:Number;
		private var oldW:Number;
		private var oldH:Number;
		private var cacheStageAlign:String;
		private var cacheStageScaleMode:String;
		
		
	/***************************************************
	* Constructor
	***************************************************/
		public function MaruComponent()
		{
			Log.dbg("MaruComponent instantiated ",Log.FUNCTION);
			possibleButtons = new Array();
			possibleButtons.push("playpause_btn","play_btn","pause_btn","stop_btn","soundoff_btn","soundon_btn","soundonoff_btn","volumeSlider","volumeRange","fullscreen_btn","timeline","playhead");
		}
		
		public function buttonClickActions(e:MouseEvent):void
		{
			if(e.target is MovieClip){
				var mcClicked:MovieClip = e.target as MovieClip;
				// Loop back out through the clicked clip structure to see if on of our favs are in it?
				var mcFound:MovieClip = findButton(mcClicked) as MovieClip;
				Log.dbg("buttonClickActions mcFound:"+mcFound);
				if(mcFound){
					var n:String = mcFound.name;
					switch(n){
						case "playpause_btn":		doPlayPause(e,mcFound);
													break;
						case "play_btn"			:	doPlay(e);
													break;
						case "pause_btn"		:	doPause(e);
													break;
						case "stop_btn"			:	doStop(e);
													break;
						case "soundoff_btn"		:	doMute(e);
													break;
						case "soundon_btn"		:	doUnmute(e);
													break;
						case "soundonoff_btn"	:	doMutetoggle(e,mcFound);
													break;
						case "fullscreen_btn"	:	toggleFullScreen(e);
													break;
						default					:	break;
					}
				} else {
					Log.dbg("You clicked on the movieclip named "+mcClicked.name+". It's not a video.Maru button",Log.INFO);
				}
			}
		}
		public function buttonDownActions(e:MouseEvent):void
		{
			if(e.target is MovieClip){
				var mcClicked:MovieClip = e.target as MovieClip;
				// Loop back out through the clicked clip structure to see if on of our favs are in it?
				var mcFound:MovieClip = findButton(mcClicked) as MovieClip;
				if(mcFound){
					var n:String = mcFound.name;
					switch(n){
						case "volumeSlider"		:	doVolumeSlider(e,mcFound);
													break;
						case "volumeRange"		:	doVolumeRange(e,mcFound);
													break;
						case "playhead"			:	doTimelineSlider(e,mcFound);
													break;
						case "timeline"			:	doTimelineRange(e,mcFound);
													break;
						default					:	break;
					}
				}
			}
		}
		public function buttonUpActions(e:MouseEvent):void
		{
			if(e.target is MovieClip){		
				var mcClicked:MovieClip = e.target as MovieClip;
				// Loop back out through the clicked clip structure to see if on of our favs are in it?
				var mcFound:MovieClip = findButton(mcClicked) as MovieClip;
				if(mcFound){
					var n:String = mcFound.name;
					switch(n){
						default					:	dropSlider(e);
													break;
					}
				}
			}
		}
		
		private function findButton(mc:DisplayObject):DisplayObject
		{
		    if( mc is MovieClip && !isButtonInArray(mc.name,possibleButtons) ){
			    mc = findButton(mc.parent);
		    }
		    return mc;
		}
		/**
		 * Checks for occurances of a string in an array
		 */
		private function isButtonInArray(name:String, arr:Array):Boolean
		{
			for (var i:uint=0; i < arr.length; i++)
		    {
		        if (arr[i] == name)
		        {
		        	return true;
		        }
		    }
		    return false;
		}
		
	/***************************************************
	* Basic playback buttons
	***************************************************/
		private function doPlay(e:MouseEvent):void
		{
			Log.dbg("MaruComponent.doPlay",Log.FUNCTION);
			player.play();
		}
		private function doPause(e:MouseEvent):void
		{
			Log.dbg("MaruComponent.doPause",Log.FUNCTION);
			player.pause();
		}
		private function doStop(e:MouseEvent):void
		{
			Log.dbg("MaruComponent.doStop",Log.FUNCTION);
			player.stop();
		}
		private function doPlayPause(e:MouseEvent, mc:MovieClip = null):void
		{
			Log.dbg("MaruComponent.doPlayPause player.isPlaying",Log.FUNCTION);
			player.playPauseToggle();
		}
		private function updateButtons(e:MaruEvent):void
		{
			Log.dbg("MaruComponent.updateButtons "+e.type,Log.FUNCTION);
			// Move to proper frame in "playpause_btn" mc (if present)
			var mcToggle:MovieClip = findMC(this.stage,"playpause_btn");
			if(mcToggle != null){
				var labels:Array = mcToggle.currentLabels;
				var labelToGoTo:String;
				if(player.isPlaying){
					labelToGoTo = "paused";
				} else {
					labelToGoTo = "playing";
				}
				
				// Look at MC to verify that the labels we need are there
				var playLabelPresent:Boolean = false;
				var pausedLabelPresent:Boolean = false;
				for (var i:uint = 0; i < labels.length; i++) {
				    var label:FrameLabel = labels[i];
				    if(label.name == "paused"){ pausedLabelPresent = true; }
				    if(label.name == "playing"){ playLabelPresent = true; }
				    if(label.name == labelToGoTo){
				    	mcToggle.gotoAndStop(label.name);
				    }
				}
				// Alert the user if any of the labels are missing
				if(!playLabelPresent || !pausedLabelPresent){
					Log.dbg("For the playpause_btn to toggle between states, it must contain the labels 'paused' and 'playing'.",Log.ERROR);
				}
			}
			
			// Move to proper frame in "mc"
			var mcMute:MovieClip = findMC(this.stage,"soundonoff_btn");
			if(mcMute != null){
				var mutelabels:Array = mcMute.currentLabels;
				if(player.isMuted){
					labelToGoTo = "on";
				} else{
					labelToGoTo = "off";
				}
				// Look at MC to verify that the labels we need are there
				var muteLabelPresent:Boolean = false;
				var unmuteLabelPresent:Boolean = false;
				for (var j:uint = 0; j < mutelabels.length; j++) {
				    var mutelabel:FrameLabel = mutelabels[j];
				    if(mutelabel.name == "off"){ muteLabelPresent = true; }
				    if(mutelabel.name == "on"){ unmuteLabelPresent = true; }
					
				    if(mutelabel.name == labelToGoTo){
				    	mcMute.gotoAndStop(mutelabel.name);
				    }
				}
				// Alert the user if any of the labels are missing
				if(!muteLabelPresent || !unmuteLabelPresent){
					Log.dbg("For the mutetoggle_btn to toggle between states, it must contain the labels 'on' and 'off'.",Log.ERROR);
				}
			}
		}
		
	/***************************************************
	* fullScreen controls
	***************************************************/  
		public function toggleFullScreen(e:MouseEvent):void
		{
			Log.dbg("MaruComponent.toggleFullScreen ",Log.FUNCTION);
			var swfStage:Stage = player.stage;
			if( swfStage.displayState == StageDisplayState.FULL_SCREEN )
			{
				swfStage.displayState = StageDisplayState.NORMAL;
			} else {
				swfStage.displayState = StageDisplayState.FULL_SCREEN;
			}
			
			if(swfStage.displayState == null){
				Log.dbg("Note: FullScreen only works in projectors or HTML files, not in the Flash IDE.",Log.ERROR);
			}
		}
		public function fullScreenRedraw(e:FullScreenEvent):void
		{
			Log.dbg("MaruComponent.fullScreenRedraw ",Log.FUNCTION);
		    if (e.fullScreen)
		    {
		    	oldX = player.x;
		    	oldY = player.y;
		    	oldW = player.width;
		    	oldH = player.height;
		    	cacheStageAlign = player.stage.align;
				cacheStageScaleMode = player.stage.scaleMode;
				player.setSize(player.stage.stageWidth,player.stage.stageHeight);
				player.x = 0;
				player.y = 0;
		    }
		    else
		    {
		        player.x = oldX;
		    	player.y = oldY;
		    	player.stage.align = cacheStageAlign;
				player.stage.scaleMode = cacheStageScaleMode;
		    	player.setSize(oldW,oldH);
		    }
		    /*
		    volumeRangeMC.visible = false;
			volumeSliderMC.visible = false;
			*/
		}
		
	/***************************************************
	* Audio handling
	***************************************************/ 
		
		private function doMute(e:MouseEvent):void
		{
			Log.dbg("MaruComponent.doMute ",Log.FUNCTION);
			player.mute();
		}
		private function doUnmute(e:MouseEvent):void
		{
			Log.dbg("MaruComponent.doUnmute ",Log.FUNCTION);
			player.unmute();
		}
		private function doMutetoggle(e:MouseEvent,mc:MovieClip = null):void
		{
			Log.dbg("MaruComponent.doMutetoggle",Log.FUNCTION);
			player.muteToggle();
		}
		
		private function doVolumeSlider(e:MouseEvent,mc:MovieClip = null):void
		{
			Log.dbg("MaruComponent.doVolumeslider",Log.FUNCTION);
			// GSet up references if have a 'mc'
			if(mc != null){
				var mcParent:DisplayObjectContainer = mc.parent; // Find the parent. The range should be on the same level for this to work.
				var rangeMC:MovieClip = mcParent.getChildByName("volumeRange") as MovieClip;
				if(rangeMC){
					volumeSliderMC = mc;
					volumeRangeMC  = rangeMC;
					applySliderListeners(volumeSliderMC,volumeRangeMC);
					dragSlider(e);
				}
			}
			
		}
		/**
		 * This function may be called before it is set up,
		 * so we include a setup in addition to the main
		 * function of moving the volumeSlider to the
		 * clicked position
		 */
		private function doVolumeRange(e:MouseEvent,mc:MovieClip = null):void
		{
			Log.dbg("MaruComponent.doVolumeRange",Log.FUNCTION);
			// TODO: This function is being called even when it should not. Gotta remove listeners on mouseUp or something  
			// Set up references if have a 'mc'
			if(mc != null && volumeRangeMC == null){
				var mcParent:DisplayObjectContainer = mc.parent; // Find the parent. The range should be on the same level for this to work.
				var sliderMC:MovieClip = mcParent.getChildByName("volumeSlider") as MovieClip;
				if(sliderMC){
					volumeSliderMC = sliderMC;
					volumeRangeMC  = mc;
					applySliderListeners(volumeSliderMC,volumeRangeMC);
				}
			}
			// Once setup, move the volumeSlider according to click
			if(volumeRangeMC != null && volumeSliderMC != null){
				// Move the slider (if required) and set percentage
				var per:Number;
				if(e.buttonDown){ // Only update slider position if the button is depressed or it will keep following!
					if(volumeRangeMC.mouseX > 0 && volumeRangeMC.mouseX < volumeRangeMC.width ){ // Set specific volume
						volumeSliderMC.x = volumeRangeMC.mouseX+volumeRangeMC.x;
						per = (volumeSliderMC.x-volumeRangeMC.x)*1/volumeRangeMC.width;
					} else if(volumeRangeMC.mouseX < 0){ // mute
						per = 0;
					} else if(volumeRangeMC.mouseX > volumeRangeMC.width){
						per = 1;
					}
					player.volume = per;
				}
			}
		}
		private function applySliderListeners(volumeSliderMC:MovieClip,volumeRangeMC:MovieClip):void
		{
			Log.dbg("MaruComponent.applySliderListeners",Log.FUNCTION);
			if(volumeSliderMC && volumeRangeMC)
			{
				if(!volumeSliderMC.hasEventListener(MouseEvent.MOUSE_DOWN) )
				{
					volumeSliderMC.addEventListener(MouseEvent.MOUSE_DOWN,dragSlider);
					volumeSliderMC.stage.addEventListener(MouseEvent.MOUSE_UP,dropSlider);
					volumeSliderMC.addEventListener(MouseEvent.MOUSE_MOVE,doVolumeRange);
					volumeRangeMC.addEventListener(MouseEvent.CLICK,doVolumeRange);
				}
			}
		}
		private function dragSlider(e:MouseEvent):void
		{
			Log.dbg("MaruComponent.dragSlider",Log.FUNCTION);
			var rect:Rectangle = new Rectangle(volumeRangeMC.x,volumeSliderMC.y,volumeRangeMC.width,0);
			volumeDragged = true;
			volumeSliderMC.startDrag(false,rect);
		}
		private function dropSlider(e:MouseEvent):void
		{
			Log.dbg("MaruComponent.dropSlider",Log.FUNCTION);
			volumeDragged = false;
			stopDrag();
		}
		
	/***************************************************
	* Timeline handling
	***************************************************/ 
	
		private function doTimelineSlider(e:MouseEvent,mc:MovieClip = null):void
		{
			Log.dbg("MaruComponent.doTimelineSlider",Log.FUNCTION);
			// GSet up references if have a 'mc'
			if(mc != null){
				var mcParent:DisplayObjectContainer = mc.parent; // Find the parent. The range should be on the same level for this to work.
				var rangeMC:MovieClip = mcParent.getChildByName("timeline") as MovieClip;
				if(rangeMC){
					playheadMC = mc;
					timelineMC  = rangeMC;
					applyTimelineListeners(playheadMC,timelineMC);
					dragTimeline(e);
				}
			}
			
		}
		
		private function updateTimeline(e:MaruEvent):void
		{
			Log.dbg("MaruComponent.updateTimeline",Log.FUNCTION);
			onPlayProgress();
		}
		
		/**
		 * This function may be called before it is set up,
		 * so we include a setup in addition to the main
		 * function of moving the volumeSlider to the
		 * clicked position
		 */
		private function doTimelineRange(e:MouseEvent,mc:MovieClip = null):void
		{
			Log.dbg("MaruComponent.doTimelineRange",Log.FUNCTION);
			// Set up references if have a 'mc'
			if(mc != null && timelineMC == null){
				var mcParent:DisplayObjectContainer = mc.parent; // Find the parent. The range should be on the same level for this to work.
				var sliderMC:MovieClip = mcParent.getChildByName("playhead") as MovieClip;
				if(sliderMC){
					playheadMC = sliderMC;
					timelineMC  = mc;
					applyTimelineListeners(playheadMC,timelineMC);
				}
			}
			if(e.buttonDown){ // Only update slider position if the button is depressed or it will keep following!
				var per:Number;
				if(timelineMC.mouseX > 0 && timelineMC.mouseX < timelineMC.width ){ // Set specific volume
					playheadMC.x = timelineMC.mouseX+timelineMC.x;
					per = (playheadMC.x-timelineMC.x)*1/timelineMC.width;
				} else if(timelineMC.mouseX < 0){ // mute
					per = 0;
				} else if(timelineMC.mouseX > timelineMC.width){
					per = 1;
				}
				player.position = player.duration*per;
			}
		}
		
		private function applyTimelineListeners(playheadMC:MovieClip,timelineMC:MovieClip):void
		{
			Log.dbg("MaruComponent.applyTimelineListeners",Log.FUNCTION);
			if(playheadMC && timelineMC)
			{
				if(!playheadMC.hasEventListener(MouseEvent.MOUSE_DOWN) )
				{
					playheadMC.addEventListener(MouseEvent.MOUSE_DOWN,dragTimeline);
					playheadMC.stage.addEventListener(MouseEvent.MOUSE_UP,dropTimeline);
					playheadMC.addEventListener(MouseEvent.MOUSE_MOVE,doTimelineRange);
					timelineMC.addEventListener(MouseEvent.CLICK,doTimelineRange);
				}
			}
		}
		private function dragTimeline(e:MouseEvent):void
		{
			Log.dbg("MaruComponent.dragTimeline",Log.FUNCTION);
			var rect:Rectangle = new Rectangle(timelineMC.x,playheadMC.y,timelineMC.width,0);
			if(!volumeDragged){
				volumeDragged = true;
				timelinePlayStatus = player.isPlaying;
				player.pause();
				playheadMC.startDrag(false,rect);
			}
		}
		private function dropTimeline(e:MouseEvent):void
		{
			Log.dbg("MaruComponent.dropTimeline ",Log.FUNCTION);
			volumeDragged = false;
			stopDrag();
			if(timelinePlayStatus){
				player.play();
			}
		}
		
		/**
		 * Will update the playback progress bar (if present)
		 */
		private function onPlayProgress():void
		{
			playbackPercent = player.position/player.duration;
			// Move the volumeSlider based on position
			if(!volumeDragged){
				if(timelineMC != null && playheadMC != null){
					// Move the slider (if required) and set percentage
					var posX:Number = timelineMC.width*playbackPercent;
					playheadMC.x = timelineMC.x + posX;
				}
			}
			// Update the progressbars (if existing)
			if(playProgressMC != null){
				// Move to the correct frame
				var nextFrame:Number = Math.floor(playProgressMC.totalFrames*playbackPercent)+1;
				playProgressMC.gotoAndStop(nextFrame);
			}
		}
		
		/**
		 * Will update the download progress bar (if present)
		 */
		private function onDownloadProgress(e:MaruEvent):void
		{
			// Update the progressbars (if existing)
			if(downloadProgressMC != null){
				// Move to the correct frame
				var nextFrame:Number = Math.floor( (downloadProgressMC.totalFrames*e.value)/100)+1;
				downloadProgressMC.gotoAndStop(nextFrame);
			}
		}
		
		/**
		 * Will try to find special movieclips (if present)
		 */
		private function locateClips():void
		{
			Log.dbg("MaruComponent.locateProgressClips ",Log.FUNCTION);
			var mcParent:DisplayObjectContainer = this.parent;
			if(playProgressMC == null){
				var mc1:MovieClip = mcParent.getChildByName("playProgress") as MovieClip;
				if(mc1){ playProgressMC = mc1; }
			}
			
			if(downloadProgressMC == null){
				var mc2:MovieClip = mcParent.getChildByName("downloadProgress") as MovieClip;
				if(mc2){ downloadProgressMC = mc2; }
			}
			
			if(playheadMC == null){
				var mc3:MovieClip = mcParent.getChildByName("playhead") as MovieClip;
				if(mc3){ playheadMC = mc3; }
			}
			
			if(timelineMC == null){
				var mc4:MovieClip = mcParent.getChildByName("timeline") as MovieClip;
				if(mc4){ timelineMC = mc4; }
			}
			
			if(volumeSliderMC == null){
				var mc5:MovieClip = mcParent.getChildByName("volumeRange") as MovieClip;
				if(mc5){ volumeSliderMC = mc5; }
			}
			
			if(volumeRangeMC == null){
				var mc6:MovieClip = mcParent.getChildByName("volumeSlider") as MovieClip;
				if(mc6){ volumeRangeMC = mc6; }
			}
		}
		
	/***************************************************
	* Component parameters
	***************************************************/
	
		[Inspectable(defaultValue="")]
		public function get filename():String
		{ 
		    return _filename;
		} 
		public function set filename(val:String):void
		{
			_filename = val; 
		}
		
		[Inspectable(name="Scale loaded content",defaultValue="noScale",enumeration="noScale,maintainAspectRatio,exactFit")] 
		public function get scaleMode():String
		{ 
		    return _scaleMode;
		} 
		public function set scaleMode(val:String):void
		{
			_scaleMode = val;
		    invalidate(InvalidationType.SIZE); 
		}
		
		[Inspectable(name="Fullscreen playback possible?",defaultValue=true)]
		public function get enableFullscreen():Boolean
		{
			return _fullscreenEnabled;
		}
		public function set enableFullscreen(val:Boolean):void
		{
			_fullscreenEnabled = val;
			invalidate(InvalidationType.SIZE);
		}
		
		[Inspectable(name="Play automatically",defaultValue=true)]
		public function get autoplay():Boolean
		{
			return _autoplay;
		}
		public function set autoplay(val:Boolean):void
		{
			_autoplay = val;
			invalidate(InvalidationType.SIZE);
		}
		
		[Inspectable(name="Rewind automatically",defaultValue=true)]
		public function get autorewind():Boolean
		{
			return _autorewind;
		}
		public function set autorewind(val:Boolean):void
		{
			_autorewind = val;
			invalidate(InvalidationType.SIZE);
		}
		
		[Inspectable(name="Scale to video",defaultValue=true)]
		public function get autosize():Boolean
		{
			return _autosize;
		}
		public function set autosize(val:Boolean):void
		{
			_autosize = val;
			invalidate(InvalidationType.SIZE);
		}
		
		[Inspectable(name="Loopmode",defaultValue="NO_LOOPING",enumeration="NO_LOOPING,LOOP_SINGLE,LOOP_ALL")]
		public function get loopmode():String
		{
			return _loopmode;
		}
		public function set loopmode(val:String):void
		{
			_loopmode = val;
			invalidate(InvalidationType.SIZE);
		}
		
		[Inspectable(name="Tray display delay",defaultValue=1)]
		public function get fadeTrayDelay():Number
		{
			return _fadeTrayDelay;
		}
		public function set fadeTrayDelay(val:Number):void
		{
			_fadeTrayDelay = val;
			invalidate(InvalidationType.SIZE);
		}
		
		[Inspectable(name="Tray fade duration",defaultValue=1)]
		public function get fadeTrayDuration():Number
		{
			return _fadeTrayDuration;
		}
		public function set fadeTrayDuration(val:Number):void
		{
			_fadeTrayDuration = val;
			invalidate(InvalidationType.SIZE);
		}
		[Inspectable(name="Debug level (0-9)",defaultValue=1)]
		public function get debug():Number
		{
			return _debug;
		}
		public function set debug(val:Number):void
		{
			_debug = val;
			Log.outputLevel = _debug;
		}
		
		private function findMC(container:DisplayObjectContainer, objName:String):MovieClip
		{
		    var child:DisplayObject;
		    var childFound:MovieClip;
		    for (var i:uint=0; i < container.numChildren; i++)
		    {
		        child = container.getChildAt(i);
		        if(container.getChildAt(i) is DisplayObjectContainer){
		        	if(!childFound){ // Only update this reference if it's not already set
			        	childFound = findMC( DisplayObjectContainer(child), objName );
			        } // If we locate the MC here, set the return variable so recursion picks it up
			        if (container.getChildAt(i) is MovieClip && child.name == objName)
			        {
			        	childFound = child as MovieClip;
			        	Log.dbg("Found "+objName+" in DisplayList!",Log.INFO);
			        }
				}
		    }
		    return childFound;
		}
		
	/***************************************************
	* Overrides
	***************************************************/
	
		/**
		 * According to http://www.adobe.com/devnet/flash/articles/creating_as3_components/creating_as3_components_pt3.pdf
		 * this method should hold our "init" code.
		 */
		override protected function configUI():void
		{
			// Turn off all output unless debug is turned on
			Log
			Log.dbg("MaruComponent.configUI - filename: "+filename,Log.FUNCTION);
		    // always call super.configUI() in your implementation
		    super.configUI();
		}
		
		override protected function checkLivePreview():Boolean
		{
			if (parent == null) { return false; }
			var className:String;
			try {
				className = getQualifiedClassName(parent);
			} catch (e:Error) {}
			return (className == "fl.livepreview::LivePreviewParent");
		}
		
		/**
		 * draw does what redraw did in as2 components, handles all drawing of the component
		 * Called automatically when the layout is invalidated
		 */
		override protected function draw():void
		{
			Log.dbg("MaruComponent.draw "+width+"."+height,Log.FUNCTION);
			// Create player if nonexistant
			if(!player){
				player = new MaruPlayer();
				addChild(player);
				player.stage.addEventListener(MouseEvent.CLICK,buttonClickActions);
				player.stage.addEventListener(MouseEvent.MOUSE_DOWN,buttonDownActions);
				player.stage.addEventListener(MouseEvent.MOUSE_UP,buttonUpActions);
				player.addEventListener(MaruEvent.CHANGED,updateButtons);
				player.addEventListener(MaruEvent.PLAY_PROGRESS,updateTimeline);
				player.addEventListener(MaruEvent.DOWNLOAD_PROGRESS,onDownloadProgress);
				player.verbose = false;
				updatePlayerProps();
				
				// Fullscreen listener stuff
				var swfStage:Stage = player.stage;
				swfStage.scaleMode = StageScaleMode.NO_SCALE;
				swfStage.align = StageAlign.TOP_LEFT;
				swfStage.displayState = StageDisplayState.NORMAL;
				swfStage.addEventListener(FullScreenEvent.FULL_SCREEN, fullScreenRedraw);
				
				if(_filename != "" && _filename != null){
					player.playfile(_filename);
				// Display trace-help if no filename is set on component
				} else {
					Log.dbg("Click the video.Maru component on stage, open the Properties panel (Window -> Properties) and click the Parameters tab to select the video to play.");
				}
			} else {
				updatePlayerProps();
			}
			
			// always call super.draw() at the end 
			super.draw();
			// Make sure we have the MC's we need
			locateClips();
		}
		private function updatePlayerProps():void
		{
			// Update player properties
			player.width  = width;
			player.height = height;
			player.autoplay = autoplay;
			player.autosize = autosize;
			player.autorewind = autorewind;
			player.fullscreen = _fullscreenEnabled;
			player.scaleMode = _scaleMode;
		}
		// Tag for validation
		private function doValidate(e:MaruEvent):void
		{
			Log.dbg("MaruComponent.doValidate",Log.FUNCTION);
			invalidate(InvalidationType.ALL,false); 
		}
		// Set invalidation and redraw right away
		override public function validateNow():void
		{ 
			Log.dbg("MaruComponent.validateNow",Log.FUNCTION);
			invalidate(InvalidationType.ALL,false); 
			draw(); 
		} 
		// Called when a change in the player occurs 
		public function drawFromHandler(e:MaruEvent):void
		{
			Log.dbg("MaruComponent.drawFromHandler "+e.type,Log.FUNCTION);
			drawNow();
		}
		// Does what it says...
		override public function drawNow():void
		{ 
			Log.dbg("MaruComponent.drawNow",Log.FUNCTION);
			draw(); 
		}
	}
}



























































